<template>
  <div idm-ctrl="idm_module" :id="moduleObject.id" :idm-ctrl-id="moduleObject.id" class="IGantt_app" >
    <div v-if="propData.showViewTypeRadio" class="header flex_end">
      <a-radio-group v-model="viewType" @change="changeViewType" button-style="solid">
        <a-radio-button v-for="(item) in viewTypeList" :value="item.value" :key="item.value">
          {{item.label}}
        </a-radio-button>
      </a-radio-group>
    </div>
    <div ref="ganttContainer" class="main" :style="{height: propData.showViewTypeRadio ? 'calc(100% - 50px)' : '100%'}"></div>
  </div>
</template>

<script>
import dayjs from 'dayjs';
import { gantt } from 'dhtmlx-gantt';
import 'dhtmlx-gantt/codebase/dhtmlxgantt.css';
import { getGanttChartData } from "@/mockData"
export default {
  name: 'IGantt',
  data(){
    return {
      moduleObject:{},
      propData:this.$root.propData.compositeAttr||{
        showViewTypeRadio: true,
      },
      data_list: [],
      viewType: 'day',
      viewTypeList: [
        {
          label: "日",
          value: "day"
        },
        {
          label: "周",
          value: "week"
        },
        {
          label: "月",
          value: "month"
        },
        {
          label: "季度",
          value: "quarter"
        },
        {
          label: "年",
          value: "year"
        }
      ],
      colorList: [
        "#2E5AAC",
        "#6A4C93",

        "#5DBE8A",
        "#FFA726",

        "#FFD700",
        "#4CAF50",

        "#26C6DA",
        "#388E3C",
        "#9E9E9E"
      ]
    }
  },
  props: {
  },
  created() {
    this.moduleObject = this.$root.moduleObject;
    if(this.propsData?.viewTypeDefault){
      this.viewType = this.propsData.viewTypeDefault;
    }
    this.convertAttrToStyleObject();
  },
  mounted() {
    this.initGantt()
    this.getInitData()
  },
  destroyed() {
    if (gantt.$destructor) {
      gantt.$destructor();
    }
  },
  methods:{
    getInitData() {
      if(this.propData?.dataSource?.length){
        var params = this.commonParam();
        let newParam = null;
        let that = this;
        params = this.makeParamsData(params);
        newParam = { ...params };
        IDM.datasource.request(
          this.propData.dataSource[0].id,
          {
            moduleObject: this.moduleObject,
            param: {
              ...newParam,
            },
          },
          function (res) {
            if (res && res.length) {
              let data_list = res.map((item,index) => {
                return {
                  ...item,
                  text: item.name,
                  duration: 0,
                  start_date: item.startDate ? item.startDate?.split(' ')?.[0] : dayjs().format('YYYY-MM-DD'),
                  end_date: item.endDate ? dayjs(`${item.endDate?.split(' ')?.[0]} 23:59:59`).toDate() : dayjs().format('YYYY-MM-DD'),
                  actual_start: item.actualStartDate ? item.actualStartDate?.split(' ')?.[0] : undefined,
                  actual_end: item.actualEndDate ? `${item.actualEndDate?.split(' ')?.[0]} 23:59:59` : undefined,
                  mainColor: that.colorList[index],
                  color: `${that.colorList[index]}54`,
                }
              });
              that.data_list = data_list;
              that.$nextTick(() => {
                that.makeGanttData()
              })
            }
          },
          function (error) {
            //这里是请求失败的返回结果
            console.log("error", error);
          }
        );
      } else { 
        let data_list = getGanttChartData();
        this.data_list = data_list.map((item,index) => {
          return {
            ...item,
            text: item.name,
            duration: 0,
            start_date: item.startDate ? item.startDate?.split(' ')?.[0] : dayjs().format('YYYY-MM-DD'),
            end_date: item.endDate ? dayjs(`${item.endDate?.split(' ')?.[0]} 23:59:59`).toDate() : dayjs().format('YYYY-MM-DD'),
            actual_start: item.actualStartDate ? item.actualStartDate?.split(' ')?.[0] : undefined,
            actual_end: item.actualEndDate ? `${item.actualEndDate?.split(' ')?.[0]} 23:59:59` : undefined,
            mainColor: this.colorList[index],
            color: `${this.colorList[index]}54`,
          }
        });
        this.$nextTick(() => {
          this.makeGanttData()
        })
      }
    },
    makeParamsData(data) {
      let result = {};
      if (
        this.propData.paramsMakeFunction &&
        this.propData.paramsMakeFunction.length &&
        window[this.propData.paramsMakeFunction[0].name]
      ) {
        result = window[this.propData.paramsMakeFunction[0].name].call(this, {
          ...data,
          ...this.propData.paramsMakeFunction[0].param,
          moduleObject: this.moduleObject,
        });
        console.log("自定义参数函数", result);
        return result;
      }
      return data;
    },
    changeViewType(){
      this.setStartEndDate();
      gantt.ext.zoom.setLevel(this.viewType);
    },
    initGantt() {
      gantt.i18n.setLocale("cn");
      gantt.config.date_format = "%Y-%m-%d";
      
      gantt.config.row_height = 40;
      gantt.config.bar_height = 30;
      this.setScalesBar();
      this.disabledOperate();
      gantt.config.columns = [
        {
          name: "text", 
          label: "里程碑", 
          align: "left", 
          width: 140,
          template: function (task) {
            return `<span style='font-weight:bold;color:#23272A'>${task.name}</span>`;
          }
        },
        // {
        //   name: "status", 
        //   label: "当前状态", 
        //   align: "center", 
        //   width: 120
        // },
        {
          name: "leader", 
          label: "项目负责人", 
          align: "center", 
          width: 110
        },
        {
          name: "startDate", 
          label: "开始日期", 
          align: "center", 
          width: 110,
          template:function (item) {
            return item.startDate?.split(' ')?.[0]
          }
        },
        {
          name: "endDate", 
          label: "结束日期", 
          align: "center", 
          width: 110,
          template:function (item) {
            return item.endDate?.split(' ')?.[0]
          }
        }
      ];
      // 初始化甘特图
      gantt.init(this.$refs.ganttContainer);
      gantt.attachEvent("onDataRender", function(){
        // 遍历每一个任务，并创建dom元素
        const row_height = gantt.config.row_height;
        let dom, leftActual, leftActualEnd
        gantt.eachTask(function(task) {
          dom = document.createElement('div');
          if(task.actual_start && task.actual_end){
            dom.style.position = 'absolute';
            dom.style.top = task.$index * row_height + 10 + 'px';
            leftActual = gantt.posFromDate(dayjs(task.actual_start).toDate());
            leftActualEnd = gantt.posFromDate(dayjs(task.actual_end).toDate());
            dom.style.left = leftActual + 'px';
            dom.style.width = (leftActualEnd - leftActual) + 'px';
            dom.style.height = '20px';
            dom.style.borderRadius = '4px';
            dom.style.backgroundColor = task.mainColor;
            // 插入到gantt_bars_area类名下面
            if(document.querySelector('.gantt_bars_area')){
              document.querySelector('.gantt_bars_area').appendChild(dom);
            }
          }
        })
      });
    },
    makeGanttData() {
      this.setStartEndDate();
      gantt.parse({
        data: this.data_list
      });
    },
    setStartEndDate() {
      const { minDate, maxDate } = this.getMinAndMaxDate(this.data_list);
      console.log(minDate, maxDate);
      if(minDate && maxDate){
        // 方法1：禁用自动调整
        gantt.config.autofit = false;
        gantt.config.start_date = dayjs(minDate).subtract(this.viewType == 'day' ? 4 : 1, this.viewType).toDate();
        gantt.config.end_date = dayjs(maxDate).add(this.viewType == 'day' ? 4 : 1, this.viewType).toDate();
        console.log(gantt.config.start_date, gantt.config.end_date);
      }
    },
    getMinAndMaxDate(data) {
      if(!data?.length){
        return {
          minDate: null,
          maxDate: null
        }
      }
      let minDate,maxDate,flag;
      data.forEach((item) => { 
        if(item.start_date && item.actual_start){
          flag = dayjs(item.start_date).isBefore(item.actual_start);
        } else if(item.start_date){
          flag = true;
        } else {
          flag = false;
        }
        if(!minDate){
          minDate = flag ?  item.start_date : item.actual_start;
        } else if(flag && dayjs(item.start_date).isBefore(minDate)) {
          minDate = item.start_date;
        } else if(dayjs(item.actual_start).isBefore(minDate) && !flag) {
          minDate = item.actual_start;
        }
        if(item.end_date && item.actual_end){
          flag = dayjs(item.end_date).isAfter(item.actual_end);
        } else if(item.end_date){
          flag = true;
        } else {
          flag = false;
        } 
        if(!maxDate){
          maxDate = flag ?  item.end_date : item.actual_end;
        } else if(flag && dayjs(item.end_date).isAfter(maxDate)) {
          maxDate = item.end_date;
        } else if(dayjs(item.actual_end).isAfter(maxDate) && !flag) {
          maxDate = item.actual_end;
        }
      });
      return {
        minDate,
        maxDate
      }
    },
    setScalesBar() {
      const zoomConfig = {
        levels: [
          {
            name: "day",
            scale_height: 55,
            min_column_width: 40,
            scales: [
              {unit: "month", step: 1, format: "%M"},
              {unit: "year", step: 1, format: "%Y"},
              {unit: "day", format: "%d"}
            ],
          },
          {
            name: "week",
            scale_height: 55,
            min_column_width: 40,
            scales: [
              {unit: "month", step: 1, format: "%M"},
              {unit: "year", step: 1, format: "%Y"},
              { unit: "week", step: 1, date: "%W周" }
            ],
          },
          {
            name:"month",
            scale_height: 50,
            min_column_width:120,
            scales:[
              {unit: "month", format: "%F, %Y"}
              // {unit: "week", format: "%W周"}
            ]
          },
          {
            name:"quarter",
            height: 50,
            min_column_width:90,
            scales:[
              {unit: "year", step: 1, format: "%Y"},
              {unit: "month", step: 1, format: "%M"},
              {
                unit: "quarter", step: 1, format: function (date) {
                  const dateToStr = gantt.date.date_to_str("%M");
                  const endDate = gantt.date.add(date, 2 - date.getMonth() % 3, "month");
                  return dateToStr(date) + " - " + dateToStr(endDate);
                }
              }
            ]
          },
          {
            name:"year",
            scale_height: 50,
            min_column_width: 30,
            scales:[
              {unit: "year", step: 1, format: "%Y"}
            ]
          }
        ],
      };
      gantt.ext.zoom.init(zoomConfig);
      gantt.ext.zoom.setLevel(this.viewType);
    },
    disabledOperate() {
      gantt.config.drag_move = false;
      gantt.config.drag_resize = true;
      gantt.config.drag_progress = false;
      gantt.config.drag_links = false;
      gantt.config.create_task = false;
      gantt.config.create_link = false;
      gantt.config.delete_task = false;
      gantt.config.delete_link = false;
      gantt.attachEvent("onTaskDblClick", function () {
        return false;
      });
    },
    /**
     * 提供父级组件调用的刷新prop数据组件
     */
    propDataWatchHandle(propData){
      this.propData = propData.compositeAttr||{};
      this.convertAttrToStyleObject();
    },
    /**
     * 把属性转换成样式对象
     */
    convertAttrToStyleObject(){
      var styleObject = {};
      if(this.propData.bgSize&&this.propData.bgSize=="custom"){
        styleObject["background-size"]=(this.propData.bgSizeWidth?this.propData.bgSizeWidth.inputVal+this.propData.bgSizeWidth.selectVal:"auto")+" "+(this.propData.bgSizeHeight?this.propData.bgSizeHeight.inputVal+this.propData.bgSizeHeight.selectVal:"auto")
      }else if(this.propData.bgSize){
        styleObject["background-size"]=this.propData.bgSize;
      }
      if(this.propData.positionX&&this.propData.positionX.inputVal){
        styleObject["background-position-x"]=this.propData.positionX.inputVal+this.propData.positionX.selectVal;
      }
      if(this.propData.positionY&&this.propData.positionY.inputVal){
        styleObject["background-position-y"]=this.propData.positionY.inputVal+this.propData.positionY.selectVal;
      }
      for (const key in this.propData) {
        if (this.propData.hasOwnProperty.call(this.propData, key)) {
          const element = this.propData[key];
          if(!element&&element!==false&&element!=0){
            continue;
          }
          switch (key) {
            case "width":
            case "height":
              styleObject[key]=element;
              break;
            case "bgColor":
              if(element&&element.hex8){
                styleObject["background-color"]=element.hex8;
              }
              break;
            case "box":
              if(element.marginTopVal){
                styleObject["margin-top"]=`${element.marginTopVal}`;
              }
              if(element.marginRightVal){
                styleObject["margin-right"]=`${element.marginRightVal}`;
              }
              if(element.marginBottomVal){
                styleObject["margin-bottom"]=`${element.marginBottomVal}`;
              }
              if(element.marginLeftVal){
                styleObject["margin-left"]=`${element.marginLeftVal}`;
              }
              if(element.paddingTopVal){
                styleObject["padding-top"]=`${element.paddingTopVal}`;
              }
              if(element.paddingRightVal){
                styleObject["padding-right"]=`${element.paddingRightVal}`;
              }
              if(element.paddingBottomVal){
                styleObject["padding-bottom"]=`${element.paddingBottomVal}`;
              }
              if(element.paddingLeftVal){
                styleObject["padding-left"]=`${element.paddingLeftVal}`;
              }
              break;
            case "bgImgUrl":
              styleObject["background-image"]=`url(${window.IDM.url.getWebPath(element)})`;
              break;
            case "positionX":
              //背景横向偏移
              
              break;
            case "positionY":
              //背景纵向偏移
              
              break;
            case "bgRepeat":
              //平铺模式
                styleObject["background-repeat"]=element;
              break;
            case "bgAttachment":
              //背景模式
                styleObject["background-attachment"]=element;
              break;
            case "border":
              if(element.border.top.width>0){
                styleObject["border-top-width"]=element.border.top.width+element.border.top.widthUnit;
                styleObject["border-top-style"]=element.border.top.style;
                if(element.border.top.colors.hex8){
                  styleObject["border-top-color"]=element.border.top.colors.hex8;
                }
              }
              if(element.border.right.width>0){
                styleObject["border-right-width"]=element.border.right.width+element.border.right.widthUnit;
                styleObject["border-right-style"]=element.border.right.style;
                if(element.border.right.colors.hex8){
                  styleObject["border-right-color"]=element.border.right.colors.hex8;
                }
              }
              if(element.border.bottom.width>0){
                styleObject["border-bottom-width"]=element.border.bottom.width+element.border.bottom.widthUnit;
                styleObject["border-bottom-style"]=element.border.bottom.style;
                if(element.border.bottom.colors.hex8){
                  styleObject["border-bottom-color"]=element.border.bottom.colors.hex8;
                }
              }
              if(element.border.left.width>0){
                styleObject["border-left-width"]=element.border.left.width+element.border.left.widthUnit;
                styleObject["border-left-style"]=element.border.left.style;
                if(element.border.left.colors.hex8){
                  styleObject["border-left-color"]=element.border.left.colors.hex8;
                }
              }
              
              styleObject["border-top-left-radius"]=element.radius.leftTop.radius+element.radius.leftTop.radiusUnit;
              styleObject["border-top-right-radius"]=element.radius.rightTop.radius+element.radius.rightTop.radiusUnit;
              styleObject["border-bottom-left-radius"]=element.radius.leftBottom.radius+element.radius.leftBottom.radiusUnit;
              styleObject["border-bottom-right-radius"]=element.radius.rightBottom.radius+element.radius.rightBottom.radiusUnit;
              break;
            case "font":
              styleObject["font-family"]=element.fontFamily;
              if(element.fontColors.hex8){
                styleObject["color"]=element.fontColors.hex8;
              }
              styleObject["font-weight"]=element.fontWeight&&element.fontWeight.split(" ")[0];
              styleObject["font-style"]=element.fontStyle;
              styleObject["font-size"]=element.fontSize+element.fontSizeUnit;
              styleObject["line-height"]=element.fontLineHeight+(element.fontLineHeightUnit=="-"?"":element.fontLineHeightUnit);
              styleObject["text-align"]=element.fontTextAlign;
              styleObject["text-decoration"]=element.fontDecoration;
              break;
          }
        }
      }
      window.IDM.setStyleToPageHead(this.moduleObject.id,styleObject);
      this.initData();
    },
    /**
     * 通用的url参数对象
     * 所有地址的url参数转换
     */
    commonParam(){
      let urlObject = IDM.url.queryObject();
      var params = {
        pageId:
          window.IDM.broadcast && window.IDM.broadcast.pageModule
            ? window.IDM.broadcast.pageModule.id
            : "",
        urlData: JSON.stringify(urlObject),
      };
      return params;
    },
    /**
     * 重新加载
     */
    reload(){
      //请求数据源
      this.initData();
    },
    /**
     * 加载动态数据
     */
    initData(){
      let that = this;
      //所有地址的url参数转换
      var params = that.commonParam();
      switch (this.propData.dataSourceType) {
        case "customInterface":
          this.propData.customInterfaceUrl&&window.IDM.http.get(this.propData.customInterfaceUrl,params)
          .then((res) => {
            //res.data
            that.$set(that.propData,"fontContent",that.getExpressData("resultData",that.propData.dataFiled,res.data));
            // that.propData.fontContent = ;
          })
          .catch(function (error) {
            
          });
          break;
        case "pageCommonInterface":
          //使用通用接口直接跳过，在setContextValue执行
          break;
        case "customFunction":
          if(this.propData.customFunction&&this.propData.customFunction.length>0){
            var resValue = "";
            try {
              resValue = window[this.propData.customFunction[0].name]&&window[this.propData.customFunction[0].name].call(this,{...params,...this.propData.customFunction[0].param,moduleObject:this.moduleObject});
            } catch (error) {
            }
            that.propData.fontContent = resValue;
          }
          break;
      }
    },
    /**
     * 通用的获取表达式匹配后的结果
     */
    getExpressData(dataName,dataFiled,resultData){
      //给defaultValue设置dataFiled的值
      var _defaultVal = undefined;
      if(dataFiled){
        var filedExp = dataFiled;
        filedExp =
          dataName +
          (filedExp.startsWiths("[") ? "" : ".") +
          filedExp;
        var dataObject = { IDM: window.IDM };
        dataObject[dataName] = resultData;
        _defaultVal = window.IDM.express.replace.call(
          this,
          "@[" + filedExp + "]",
          dataObject
        );
      }
      //对结果进行再次函数自定义
      if(this.propData.customFunction&&this.propData.customFunction.length>0){
        var params = this.commonParam();
        var resValue = "";
        try {
          resValue = window[this.propData.customFunction[0].name]&&window[this.propData.customFunction[0].name].call(this,{
            ...params,
            ...this.propData.customFunction[0].param,
            moduleObject:this.moduleObject,
            expressData:_defaultVal,interfaceData:resultData
          });
        } catch (error) {
        }
        _defaultVal = resValue;
      }
      
      return _defaultVal;
    },
    /**
     * 文本点击事件
     */
    textClickHandle(){
      let that = this;
      if(this.moduleObject.env=="develop"){
        //开发模式下不执行此事件
        return;
      }
      //获取所有的URL参数、页面ID（pageId）、以及所有组件的返回值（用范围值去调用IDM提供的方法取出所有的组件值）
      let urlObject = window.IDM.url.queryObject(),
      pageId = window.IDM.broadcast&&window.IDM.broadcast.pageModule?window.IDM.broadcast.pageModule.id:"";
      //自定义函数
      /**
       * [
       * {name:"",param:{}}
       * ]
       */
      var clickFunction = this.propData.clickFunction;
      clickFunction&&clickFunction.forEach(item=>{
        window[item.name]&&window[item.name].call(this,{
          urlData:urlObject,
          pageId,
          customParam:item.param,
          _this:this
        });
      })
    },
    showThisModuleHandle(){
      this.propData.defaultStatus = "default";
    },
    hideThisModuleHandle(){
      this.propData.defaultStatus = "hidden";
    },
    /**
     * 组件通信：接收消息的方法
     * @param {
     *  type:"发送消息的时候定义的类型，这里可以自己用来要具体做什么，统一规定的type：linkageResult（组件联动传结果值）、linkageDemand（组件联动传需求值）、linkageReload（联动组件重新加载）
     * 、linkageOpenDialog（打开弹窗）、linkageCloseDialog（关闭弹窗）、linkageShowModule（显示组件）、linkageHideModule（隐藏组件）、linkageResetDefaultValue（重置默认值）"
     *  message:{发送的时候传输的消息对象数据}
     *  messageKey:"消息数据的key值，代表数据类型是什么，常用于表单交互上，比如通过这个key判断是什么数据"
     *  isAcross:如果为true则代表发送来源是其他页面的组件，默认为false
     * } object 
     */
    receiveBroadcastMessage(object){
      console.log("组件收到消息",object)
      if(object.type&&object.type=="linkageShowModule"){
        this.showThisModuleHandle();
      }else if(object.type&&object.type=="linkageHideModule"){
        this.hideThisModuleHandle();
      }
    },
    /**
     * 组件通信：发送消息的方法
     * @param {
     *  type:"自己定义的，统一规定的type：linkageResult（组件联动传结果值）、linkageDemand（组件联动传需求值）、linkageReload（联动组件重新加载）
     * 、linkageOpenDialog（打开弹窗）、linkageCloseDialog（关闭弹窗）、linkageShowModule（显示组件）、linkageHideModule（隐藏组件）、linkageResetDefaultValue（重置默认值）",
     *  message:{实际的消息对象},
     *  rangeModule:"为空发送给全部，根据配置的属性中设定的值（值的内容是组件的packageid数组），不取子表的，比如直接 this.$root.propData.compositeAttr["attrKey"]（注意attrKey是属性中定义的bindKey）,这里的格式为：['1','2']"",
     *  className:"指定的组件类型，比如只给待办组件发送，然后再去过滤上面的值"
     *  globalSend:如果为true则全站发送消息，注意全站rangeModule是无效的，只有className才有效，默认为false
     * } object 
     */
    sendBroadcastMessage(object){
        window.IDM.broadcast&&window.IDM.broadcast.send(object);
    },
    /**
     * 交互功能：设置组件的上下文内容值
     * @param {
     *  type:"定义的类型，已知类型：pageCommonInterface（页面统一接口返回值）、"
     *  key:"数据key标识，页面每个接口设置的数据集名称，方便识别获取自己需要的数据"
     *  data:"数据集，内容为：字符串 or 数组 or 对象"
     * }
     */
    setContextValue(object) {
      console.log("统一接口设置的值", object);
      if (object.type != "pageCommonInterface") {
        return;
      }
      //这里使用的是子表，所以要循环匹配所有子表的属性然后再去设置修改默认值
      if (object.key == this.propData.dataName) {
        // this.propData.fontContent = this.getExpressData(this.propData.dataName,this.propData.dataFiled,object.data);
        this.$set(this.propData,"fontContent",this.getExpressData(this.propData.dataName,this.propData.dataFiled,object.data));
      }
    }
  }
}
</script>
<style lang="scss" scoped>
.IGantt_app{
  height: 100vh;
  &>.header{
    height: 50px;
  }
  &>.main{
    height: calc(100% - 50px);
  }
}
</style>
<style lang="scss">
.IGantt_app{
  .gantt_layout_content{
    .gantt_grid_scale{
      .gantt_grid_head_cell{
        font-size: 14px;
        color: #23272A;
        font-weight: bold;
        border-right: 1px solid #f0f0f0 !important;
        &:last-child{
          border-right: none !important;
        }
      }
    }
    .gantt_task_line{
      border: none;
    }
    .gantt_row_task.gantt_selected{
      background: #E0E5F336 !important;
    }
    .gantt_task_row.gantt_selected{
      background: #E0E5F336 !important;
    }
    .gantt_grid_data .gantt_row.odd:hover, .gantt_grid_data .gantt_row:hover{
      background: #e0e0e0 !important;
    }
    .gantt_task_row.gantt_selected .gantt_task_cell{
      border-right: 1px solid #ebebeb;
    }
  }
}

</style>